
#include "SortTimer.h"
#include "cc_pub.h"
#include "cc_malloc.h"		// 依赖 malloc/free 
#include "Macro_DLink.h"	// 宏
// #include "GDLink.h"		// tDLQNode 定义

#define CFG_RWLOCK_CHECK 

#define LLOG
#define LLOG_ERR
#define LLOG_MARK
#include "llog.h"

#ifdef	CFG_SYS_MALLOC

#define L_MALLOC 	MALLOC
#define L_FREE 		MFREE

#else
	
	#ifdef	CFG_STATIC_BUF_ALLOCATE

	#define L_MALLOC 	SMalloc
	#define L_FREE(A) 	do{LLOG_ERR(); while(1); }while(0);

	#else 

	#include <stdlib.h>
	#define L_MALLOC(A) malloc(A)
	#define L_FREE(A)	free(A)

	#endif

#endif

/********* interior  struct **********/
//
struct CC_Sort_Timer{ // Ptr*4 +2*tMs +4 = 28Byte
	tDLNode DNode;	// Fixed At Frist
	tMs StartTick;
	tMs PeriodTick; // DlyTick
	
	uint8_t TimerTyp; // Once ,Period;
	uint8_t OnceFlag;	//
	uint8_t State;	//
	uint8_t Id;	//
	//
	int (*pFunc)(void* pPara);
	void* pPara;
};

struct CC_Sort_Timer_Management{
	tDLNode* pHead;
	uint16_t Cnt;
};

/******* global val ***************/
static uint8_t g_STimer_IdCnt = 0x80;
/******* local function **************/

/******* TODO ************************/

#ifdef CFG_SORT_TIMER // Node STimer API

static tSTimer* STimer_Create(uint8_t Id,uint8_t TimerTyp,tMs PeriodTick){
	
	tSTimer* ptmp = NULL;
	
	if(Id == 0)	{ LLOG_ERR(); return ptmp; }
	
	ptmp = (tSTimer*)L_MALLOC(sizeof(tSTimer));
	if(ptmp == NULL){
		LLOG_ERR();
		return ptmp;
	}
	
	MEMSET((uint8_t*)ptmp,0,sizeof(tSTimer));
	ptmp->TimerTyp = TimerTyp; 
	ptmp->PeriodTick = PeriodTick; 
	ptmp->Id = Id; 

	return ptmp;
}

void STimer_Show(tSTimer* pObj){
	
	if(pObj == NULL)	{LLOG_ERR(); return;}
	
	LLOG("#I STimer\n");
	LLOG("#I StartTick 	=[%x]\n",pObj->StartTick);
	LLOG("#I PeriodTick =[%x]\n",pObj->PeriodTick);
	LLOG("#I TimerTyp 	=[%x]\n",pObj->TimerTyp);
	LLOG("#I OnceFlag 	=[%x]\n",pObj->OnceFlag);
	LLOG("#I State		=[%x]\n",pObj->State);
	LLOG("#I Id			=[%x]\n",pObj->Id);
	LLOG("#I pFunc		=[%x]\n",pObj->pFunc);
	LLOG("#I pPara		=[%x]\n",pObj->pPara);
	
}

int STimer_BindCBF(tSTimer* pObj, int (*pFunc)(void*) ){
	
	int ret=RET_ERR;
	
	if(pObj == NULL) { LLOG_ERR(); return ret; }
	
	ret = RET_OK;
	pObj->pFunc = pFunc;
	
	return ret;
}

int STimer_BindPara(tSTimer* pObj, void* pPara ){
	
	int ret=RET_ERR;
	
	if(pObj == NULL) { LLOG_ERR(); return ret; }
	
	ret = RET_OK;
	pObj->pPara = pPara;
	
	return ret;
}

int STimer_OnOff(tSTimer* pObj, uint8_t OnOff){
	
	int ret=RET_ERR;
	
	if(pObj == NULL) { LLOG_ERR(); return ret; }
	
	ret = RET_OK;
	if(OnOff  == 0){ // close
		pObj->State = 0;
	}
	else{
		pObj->State = 1;
		pObj->StartTick = GetNowTick();
		if(pObj->TimerTyp&STIMER_TYP_ONCE){
			pObj->OnceFlag = 1;
		}
	}
	
	return ret;
}

#endif

#ifdef CFG_SORT_TIMER // STimerMgm API

tSTimerMgm* STimerMgm_Create(void){
	
	tSTimerMgm* ptmp = NULL;
		
	ptmp = (tSTimerMgm*)L_MALLOC(sizeof(tSTimerMgm));
	if(ptmp == NULL){
		LLOG_ERR();
		return ptmp;
	}
	
	MEMSET((uint8_t*)ptmp,0,sizeof(tSTimerMgm));

	return ptmp;
}

static int STimerMgm_AddToLink(tSTimerMgm* pObj,tSTimer* pTimer){
	//
	int ret = RET_ERR;
	
    tDLNode* ptmp;
    tDLNode* pAddNode;
	
	if(pObj == NULL) 		{ LLOG_ERR(); return ret;}
	if(pAddNode	== NULL) 	{ LLOG_ERR(); return ret;}
	
	pAddNode = &pTimer->DNode;
	
	ret=RET_OK;
    if(pObj->pHead == NULL){ 
		GDLNODE_INSERT_LOOPHEAD(pObj->pHead,pAddNode);
		pObj->Cnt++;
		return ret;
	}   
    
	ptmp=pObj->pHead;
	GDLNODE_INSERT_BEFORE(pObj->pHead,ptmp,pAddNode);
	pObj->Cnt++;
	
	return ret;
}

static int STimerMgm_RemoveFormLink(tSTimerMgm* pObj,tSTimer* pTimer){
	// 
	int ret = RET_ERR;
	
    tDLNode* ptmp = NULL;
    tDLNode* pRemoveNode = NULL;
	
	if(pObj == NULL) 			{ LLOG_ERR(); return ret;}
	if(pObj->pHead == NULL) 	{ LLOG_ERR(); return ret;}
	if(pTimer == NULL) 			{ LLOG_ERR(); return ret;}
	
	pRemoveNode = &pTimer->DNode;
    ptmp = pObj->pHead;
    while(1){
		
        if( pRemoveNode == ptmp){ // Check_IsDLinkNode
            break;
        } 
		
		// GDLINK_ITERATOR_DOWN(pObj->pHead,ptmp); 
		ptmp = ptmp->pNext;\
		if( (ptmp == pObj->pHead) || (ptmp == NULL)){
			ptmp = NULL;
			break;
		}
	}
	
    if(ptmp != NULL){
		
		GDLNODE_REMOVE(pObj->pHead,ptmp);
		if(pObj->Cnt > 0){
			pObj->Cnt--;
		}
		else{
			LLOG_ERR();
		}
		ret=RET_OK;
	}	
	
	return ret;
}

int STimerMgm_MsTick_CallBack(tSTimerMgm* pObj){
	// 周期调用
	int ret=RET_ERR;
    tDLNode* ptmp=NULL;
    tSTimer* pTimer=NULL;

	if(pObj == NULL) 			{ LLOG_ERR(); return ret;}
	// if(msTick == 0)				{ LLOG_ERR(); return ret;}
	if(pObj->pHead == NULL)		{ LLOG_ERR(); return ret;}	

	// ret=RET_OK;
	ptmp=pObj->pHead;
    while(1){
		pTimer = (tSTimer*)ptmp;
		
		//
		if(pTimer->State != 0){
			if(pTimer->TimerTyp&STIMER_TYP_ONCE){
				if(pTimer->OnceFlag == 1){
					if(Check_TimeOut(pTimer->StartTick,pTimer->PeriodTick) == RET_OT){
						pTimer->OnceFlag = 0;
						
						if(pTimer->pFunc != NULL){
							ret = pTimer->pFunc(pTimer->pPara);
						}
					}
				}
			}
			else { // period
				if(Check_TimeOut(pTimer->StartTick,pTimer->PeriodTick) == RET_OT){
					pTimer->StartTick = GetNowTick();
					if(pTimer->pFunc != NULL){
						ret = pTimer->pFunc(pTimer->pPara);
					}
				}			
			}
		}
		//
		// GDLINK_ITERATOR_DOWN(pObj->pHead,ptmp);
		ptmp = ptmp->pNext;\
		if( (ptmp == pObj->pHead) || (ptmp == NULL)){ 
			ptmp = NULL;
			break;
		}		
    }
    return ret;    
}

tSTimer* STimerMgm_CreateAndAdd(tSTimerMgm* pObj,uint8_t Id,uint8_t TimerTyp,tMs msTick){
	//
	tSTimer* pTimer = NULL;
	int TimerID = 0;
	int ret;
	
	if(pObj == NULL)	{LLOG_ERR(); return pTimer;}
	
	if(Id == 0){
		TimerID = g_STimer_IdCnt++;
	}
	else{
		TimerID = Id;
	}
	
	pTimer = STimer_Create(TimerID, TimerTyp, msTick);
	if(pTimer == NULL){
		LLOG_ERR();
		return pTimer;
	}
	ret = STimerMgm_AddToLink(pObj, pTimer);
	STimer_BindPara(pTimer,(void*)pTimer);	// Note: 默认绑定自身Timer对象
	
	return pTimer;
}

int STimerMgm_RemoveAndDestory(tSTimerMgm* pObj, tSTimer* pTimer){
	
	int ret = RET_ERR;

	if(pObj == NULL)	{LLOG_ERR(); return ret;}
	if(pTimer == NULL)	{LLOG_ERR(); return ret;}

	STimerMgm_RemoveFormLink(pObj,pTimer);
	
	ret = RET_OK;
	L_FREE(pTimer);
	
	return ret;
}

void STimerMgm_Show(tSTimerMgm* pObj){
	
	if(pObj == NULL)	{LLOG_ERR(); return;}
	
	LLOG("#I STimerMgm\n");
	LLOG("#I pHead=[0x%x]\n",pObj->pHead);
	LLOG("#I Cnt=[%d]\n",pObj->Cnt);
}

#endif

#ifdef CFG_APP_SORT_TIMER // 
// App
static tSTimerMgm* g_pAppSortTimer = NULL;
// static tSTimerMgm* g_pAppCoTask = NULL;	// Coroutine 
// static tSTimerMgm* g_pDrvCoTask = NULL;

int SortTimer_Init(void){
	int ret = RET_OK;
	
	g_pAppSortTimer = STimerMgm_Create();
	if(g_pAppSortTimer == NULL){
		LLOG_ERR();
		while(1);
	}
	
	return ret;
}

tSTimer* STimer_CreateAndAdd(uint8_t Id,uint8_t TimerTyp,tMs msTick){
	return STimerMgm_CreateAndAdd(g_pAppSortTimer,Id,TimerTyp,msTick);
}

int STimer_RemoveAndDestory(tSTimer* pTimer){
	return STimerMgm_RemoveAndDestory(g_pAppSortTimer,pTimer);
}

int STimer_Run(void){
	STimerMgm_MsTick_CallBack(g_pAppSortTimer);
}

void STimerX_Show(void){
	STimerMgm_Show(g_pAppSortTimer);
}

#endif

